﻿/**
* Reflection.js
* 
* @author Demis Bellot
* @version 1.0
* @requres StringExt.js, ArrayExt.js
*
* Copyright 2009, Demis Bellot
* http://code.google.com/p/ajaxstack/
*/

function Reflection() { }
var R = Reflection;
R.log = new Logger("Reflection");

R.convertAll = function(objects, factoryFn, fields)
{
	if (!objects) return [];
	var to = [];
	for (var i = 0, len = objects.length; i < len; i++)
	{
		var item = R.convert(objects[i], factoryFn, fields);
		to.push(item);
	}
	return to;
};

R.convert = function(from, factoryFn, fields)
{
	if (!from) return null;
	return R.populate(factoryFn(), from, fields);
};

R.populate = function(to, from, fields)
{
	try
	{
		if (fields)
		{
			for (var i = 0, len = fields.length; i < len; i++)
			{
				var field = fields[i];
				if (!from.hasOwnProperty(field))
				{
					R.log.error("R.populate: Field '" + field + "' does not exist!");
					continue;
				}
				R.setField(from, to, field);
			}
		}
		else
		{
			for (var field in from)
			{
				R.setField(from, to, field);
			}
		}
	}
	catch (e)
	{
		R.log.error("R.populate: convert(), message = " + e.message);
	}
	return to;
};

R.getField = function(obj, field)
{
	var CHAR_A = "A".charCodeAt(0);
	var CHAR_Z = "Z".charCodeAt(0);
	var CHAR_a = "a".charCodeAt(0);
	var CHAR_z = "z".charCodeAt(0);

	if (obj.hasOwnProperty(field))
	{
		return field;
	}

	var firstChar = field.charCodeAt(0);
	var startsWithUpper = firstChar >= CHAR_A && firstChar <= CHAR_Z;
	var startsWithLower = firstChar >= CHAR_a && firstChar <= CHAR_z;

	var altFieldName = "";
	if (startsWithUpper)
	{
		altFieldName = field.charAt(0).toLowerCase() + field.substr(1);
	}
	else if (startsWithLower)
	{
		altFieldName = field.charAt(0).toUpperCase() + field.substr(1);
	}

	return obj.hasOwnProperty(altFieldName) ? altFieldName : null;
};

R.setField = function(from, to, fromField)
{
	//Skip reserved vars prefixed with '$'
	if (!fromField || S.startsWith(fromField, "$")) return;

	//Skip functions
	var fromFieldValue = from[fromField];
	if (is.Function(fromFieldValue)) return;

	var toField = R.getField(to, fromField);

	if (toField == null)
	{
		//if the field doesn't exist on 'to' and its not a 'valueType' ignore
		if (!is.ValueType(fromFieldValue)) return;
		toField = fromField;
	}


	if (fromFieldValue == undefined)
	{
		to[toField] = undefined;
	}
	else if (fromFieldValue == null)
	{
		to[toField] = null;
	}
	else
	{
		try
		{
			to[toField] = fromFieldValue;
		}
		catch (e)
		{
			R.log.error("R.setField: Error on '" + to + "'[" + toField + "] = " + fromFieldValue);
			//Can happen when the fields are not the same type.
			//TODO: find more effiecient way to find if a field is a date
			if (is.Date(to[toField]))
			{
				to[toField] = Dto.parseDate(fromFieldValue);
			}
		}
	}
};

//Converts dates from JSON and XML to a Date
R.parseDate = function(dateObject)
{
	if (!dateObject) return null;
	if (is.Date(dateObject)) return dateObject;
	var dateStr = dateObject.toString();

	//Parse Date From String
	if (is.String(dateObject))
	{
		var dateMilliSecondsIndex = dateStr.indexOf(".");
		var isDatabaseDate = dateMilliSecondsIndex != -1;
		if (isDatabaseDate)
		{
			//Need to convert '2008-01-25 06:14:23.223' to '2008/01/25 06:14:23 GMT-0000'
			dateStr = dateStr.substr(0, dateMilliSecondsIndex);
			dateStr = dateStr.replace(/-/g, "/");
			dateStr += " GMT-0000";
			dateValue = new Date(Date.parse(dateStr));
			return dateValue;
		}
	}

	var dateValue;

	//Parse Date from WCF Json Date Value: '\/Date(-2208960000000-0800)\/'
	var isWcfJsonDate = /\/Date(.*)\//.test(dateStr);
	if (isWcfJsonDate)
	{
		dateStr = dateStr.match(/Date\((.*?)\)/)[1];
		dateValue = new Date(parseInt(dateStr));
		return dateValue;
	}
	dateValue = new Date(dateObject);
	return dateValue;
};

//converts 2005-12-25T00:00:00 to 2005/12/25 00:00:00 so it can be correctly parsed 
//by the Date() constructor
R.parseDateFromXml = function(dateObject)
{
	var dateStr = dateObject.toString();
	if (!dateStr || dateStr == "" || dateStr == null)
	{
		return new Date(0);
	}
	dateStr = dateStr.replace(/-/g, "/");
	dateStr = dateStr.replace("T", " ");
	dateStr = dateStr.replace(/\..*/, "");
	dateStr += " GMT-0000";
	return new Date(dateStr);
};

R.dateToWcfJsonDate = function(date)
{
	return "\/Date(" + date.getTime() + "-0000)\/";
};

